<?php
namespace Com\Pay;
class AibeiPay{

    private $config = array();
    private $NotifyReturn = array(); // 返回异步通知验签通过后的报文

    public function __construct($send_data){
        $this->config = $send_data;
    }

    /*生成支付连接*/
    public function getUrl($order_info){
        $price = $order_info['paymoney'];
        $notifyUrl = 'http://' . $_SERVER['HTTP_HOST'] . '/Api/NotifyCallback/AibeiPayNotify';
        $order_sn = $order_info['ordernumber'];
        $post_data = array(
            'appid' =>   $this->config['mch_id'],
            'waresid'    =>  1,
            "cporderid"  =>  $order_sn,
            'price' => floatval($price),
            'currency' => 'RMB',
            'appuserid'    => (string)"usd=" . rand(1,50000),
            'notifyurl'    => $notifyUrl,
        );
        $privareKey = file_get_contents(getcwd() . '/ThinkPHP/Library/Vendor/AiBeiCret/cert/'. $this->config['mch_id'] .'_private_key.pem');
        $reqData = $this->composeReq($post_data,$privareKey);
        $tar_url = 'http://ipay.iapppay.com:9999/payapi/order';
        $res = $this->request_by_curl($tar_url , $reqData , 'order test'); // 交易id获取
        $params = array();
        $this->parseResp($res , file_get_contents(getcwd() . '/ThinkPHP/Library/Vendor/AiBeiCret/cert/'.$this->config['mch_id'].'_public_key.pem') , $params);
        $h5pay = array(
            'tid' => $params->transid,
            'app' => $this->config['mch_id'],
            'url_r' => $notifyUrl,
            'url_h' => $order_info['return_url'],
        );
        $paySign = $this->h5composeReq($h5pay , $privareKey);
        $pay_url = 'https://web.iapppay.com/pay/gateway?' . $paySign;
        if($pay_url != ''){
            return $pay_url;
        }
        return '';
    }

    //H5请求报文拼接
   private function h5composeReq($reqJson, $vkey) {
        //获取待签名字符串
        $content = json_encode($reqJson);
        //格式化key，建议将格式化后的key保存，直接调用
        $vkey = $this->formatPriKey($vkey);

        //生成签名
        $sign = $this->sign($content, $vkey);

        //组装请求报文，目前签名方式只支持RSA这一种
        $reqData = "data=".urlencode($content)."&sign=".urlencode($sign)."&sign_type=RSA";

        return $reqData;
    }

    //回调方法，把返回数据处理成统一规定返回
    public function response(){
        $data = $_POST;
        if(empty($data)) {
            exit('fail');
        }else{
            $transdata = $data['transdata'];
            if(stripos("%22",$transdata)){ //判断接收到的数据是否做过 Urldecode处理，如果没有处理则对数据进行Urldecode处理
                $data = array_map ('urldecode',$data);
            }

            $respData = 'transdata='.$data['transdata'].'&sign='.$data['sign'].'&signtype='.$data['signtype'];//把数据组装成验签函数要求的参数格式
            $platpkey = file_get_contents(getcwd() . '/ThinkPHP/Library/Vendor/AiBeiCret/cert/'.$this->config['mch_id'].'_public_key.pem'); // 读取公钥
            if(!$this->parseResp($respData, $platpkey, $respJson)) {
                //验签失败
               return false;
            }else{
               return true;
            }
        }
        return false;
    }

    /**
     * 组装request报文
     * $reqJson 需要组装的json报文
     * $vkey  cp私钥，格式化之前的私钥
     * return 返回组装后的报文
     */
   private function composeReq($reqJson, $vkey) {
        //获取待签名字符串
        $content = json_encode($reqJson);
        //格式化key，建议将格式化后的key保存，直接调用
        $vkey = $this->formatPriKey($vkey);

        //生成签名
        $sign = $this->sign($content, $vkey);

        //组装请求报文，目前签名方式只支持RSA这一种
        $reqData = "transdata=".urlencode($content)."&sign=".urlencode($sign)."&signtype=RSA";

        return $reqData;
    }

    /**格式化公钥
     * $pubKey PKCS#1格式的公钥串
     * return pem格式公钥， 可以保存为.pem文件
     */
   private function formatPubKey($pubKey) {
        $fKey = "-----BEGIN PUBLIC KEY-----\n";
        $len = strlen($pubKey);
        for($i = 0; $i < $len; ) {
            $fKey = $fKey . substr($pubKey, $i, 64) . "\n";
            $i += 64;
        }
        $fKey .= "-----END PUBLIC KEY-----";
        return $fKey;
    }


    /**格式化公钥
     * $priKey PKCS#1格式的私钥串
     * return pem格式私钥， 可以保存为.pem文件
     */
   private function formatPriKey($priKey) {
        $fKey = "-----BEGIN RSA PRIVATE KEY-----\n";
        $len = strlen($priKey);
        for($i = 0; $i < $len; ) {
            $fKey = $fKey . substr($priKey, $i, 64) . "\n";
            $i += 64;
        }
        $fKey .= "-----END RSA PRIVATE KEY-----";
       return $fKey;
    }

    /**RSA签名
     * $data待签名数据
     * $priKey商户私钥
     * 签名用商户私钥
     * 使用MD5摘要算法
     * 最后的签名，需要用base64编码
     * return Sign签名
     */
   private function sign($data, $priKey) {
        //转换为openssl密钥
        $res = openssl_get_privatekey($priKey);

        //调用openssl内置签名方法，生成签名$sign
        openssl_sign($data, $sign, $res, OPENSSL_ALGO_MD5);

        //释放资源
        openssl_free_key($res);

        //base64编码
        $sign = base64_encode($sign);
        return $sign;
    }

    /**RSA验签
     * $data待签名数据
     * $sign需要验签的签名
     * $pubKey爱贝公钥
     * 验签用爱贝公钥，摘要算法为MD5
     * return 验签是否通过 bool值
     */
   private function verify($data, $sign, $pubKey)  {
        //转换为openssl格式密钥
        $res = openssl_get_publickey($pubKey);
        //调用openssl内置方法验签，返回bool值
        $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_MD5);
        //释放资源
        openssl_free_key($res);

        //返回资源是否成功
        return $result;
    }

    /**
     * 解析response报文
     * $content  收到的response报文
     * $pkey     爱贝平台公钥，用于验签
     * $respJson 返回解析后的json报文
     * return    解析成功TRUE，失败FALSE
     */
//   private function parseResp($content, $pkey, &$respJson) {
//        $arr=array_map(create_function('$v', 'return explode("=", $v);'), explode('&', $content));
//        foreach($arr as $value) {
//            $resp[($value[0])] = $value[1];
//        }
//
//        //解析transdata
//        if(array_key_exists("transdata", $resp)) {
//            $respJson = json_decode($resp["transdata"]);
//        } else {
//            return FALSE;
//        }
//        //验证签名，失败应答报文没有sign，跳过验签
//        if(array_key_exists("sign", $resp)) {
//            //校验签名
//            $pkey = $this->formatPubKey($pkey);
//            return $this->verify($_POST['transdata'], $resp["sign"], $pkey);
//        } else if(array_key_exists("errmsg", $respJson)) {
//            return FALSE;
//        }
//
//        return true;
//    }

    function parseResp($content, $pkey, &$respJson) {
        $arr=array_map(create_function('$v', 'return explode("=", $v);'), explode('&', $content));
        foreach($arr as $value) {
            $resp[($value[0])] = $value[1];
        }

        //解析transdata
        if(array_key_exists("transdata", $resp)) {
            $respJson = json_decode($resp["transdata"]);
        } else {
            return FALSE;
        }

        //验证签名，失败应答报文没有sign，跳过验签
        if(array_key_exists("sign", $resp)) {
            //校验签名
            $pkey = $this->formatPubKey($pkey);
            return $this->verify($_POST["transdata"], $resp["sign"], $pkey);
        } else if(array_key_exists("errmsg", $respJson)) {
            return FALSE;
        }

        return TRUE;
    }


    private function request_by_curl($remoteServer, $postData, $userAgent) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $remoteServer);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
        $data = urldecode(curl_exec($ch));
        curl_close($ch);

        return $data;
    }

}
